package io.lvdaxian.mybatis08.executor.resultset;

import io.lvdaxian.mybatis08.executor.Executor;
import io.lvdaxian.mybatis08.mapping.BoundSql;
import io.lvdaxian.mybatis08.mapping.MappedStatement;

import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 默认的结果集 处理
 *
 * @author lihh
 */
public class DefaultResultSetHandler implements ResultSetHandler {
  
  private final BoundSql boundSql;
  private final MappedStatement mappedStatement;
  private final Executor executor;
  
  public DefaultResultSetHandler(Executor executor, MappedStatement mappedStatement, BoundSql boundSql) {
    this.executor = executor;
    this.mappedStatement = mappedStatement;
    this.boundSql = boundSql;
  }
  
  
  /**
   * 结果集 处理操作
   *
   * @param stmt 传递的statement
   * @param <E>  泛型参数
   * @return 返回 集合
   * @throws SQLException 异常
   * @author lihh
   */
  @Override
  public <E> List<E> handleResultSets(Statement stmt) throws SQLException {
    // 这里 拿到结果集, 其实就是将结果集 交给这个方法来处理
    ResultSet resultSet = stmt.getResultSet();
    
    // resultSet2Obj 这里是结果集 转换处理
    return resultSet2Obj(resultSet, mappedStatement.getResultType());
  }
  
  /**
   * 将 结果Set 转换 对象
   *
   * @param resultSet 结果集
   * @param clazz     表示转换的类
   * @param <T>       动态泛型
   * @return 返回集合对象
   * @author lihh
   */
  private <T> List<T> resultSet2Obj(ResultSet resultSet, Class<?> clazz) {
    List<T> list = new ArrayList<>();
    try {
      // 结果集的 元信息
      ResultSetMetaData metaData = resultSet.getMetaData();
      // 结果集的 列个数
      int columnCount = metaData.getColumnCount();
      
      // 每次遍历行值
      while (resultSet.next()) {
        // 通过方法【newInstance】拿到实例
        T obj = (T) clazz.newInstance();
        // 遍历 列的个数
        for (int i = 1; i <= columnCount; i++) {
          // 拿到的具体的值
          Object value = resultSet.getObject(i);
          // 拿到的 列名称
          String columnName = metaData.getColumnName(i);
          // 这里尝试拼接方法 eg: setName
          String setMethod = "set" + columnName.substring(0, 1).toUpperCase() + columnName.substring(1);
          Method method;
          if (value instanceof Timestamp) {
            method = clazz.getMethod(setMethod, Date.class);
          } else {
            method = clazz.getMethod(setMethod, value.getClass());
          }
          // 指定对象 set 方法
          method.invoke(obj, value);
        }
        list.add(obj);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
    return list;
  }
}
